﻿/********************************************************************************
* Copyright 2010 Zane Thorn (zane.thorn@gmail.com)                              *
*                                                                               *
* NeturalMath is free software: you can redistribute it and/or modify           *
* it under the terms of the GNU Lesser General Public License as published by   *
* the Free Software Foundation, either version 3 of the License, or             *
* (at your option) any later version.                                           *
*                                                                               *
* NeturalMath is distributed in the hope that it will be useful,                *
* but WITHOUT ANY WARRANTY; without even the implied warranty of                *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                 *
* GNU Lesser General Public License for more details.                           *
*                                                                               *
* You should have received a copy of the GNU Lesser General Public License      *
* along with NeturalMath.  If not, see <http://www.gnu.org/licenses/>.          *
********************************************************************************/

using System;
using System.Collections;
using System.Linq.Expressions;

namespace NeturalMath
{
    /// <summary>
    /// 
    /// </summary>
    public static class Extensions
    {
        #region String Helpers

        /// <summary>
        /// Checks a given string from a provided string. The check is ran against
        /// a provided StringComparison object.
        /// </summary>
        /// <param name="source">String to search</param>
        /// <param name="toCheck">String to search for</param>
        /// <param name="comp">StringComparison method</param>
        /// <returns>True if the string is found</returns>
        public static bool Contains(this string source, string toCheck, StringComparison comp)
        {
            return source.IndexOf(toCheck, comp) >= 0;
        }

        #endregion

        #region Char Helpers

        /// <summary>
        /// Flips the bits of 
        /// </summary>
        /// <param name="t1"></param>
        /// <returns></returns>
        public static char Flip(this char t1)
        {
            var bytes = BitConverter.GetBytes(t1);
            bytes[0] = (byte)~bytes[0];
            bytes[0] = (byte)~bytes[0];
            return BitConverter.ToChar(bytes, 0);
        }

        #endregion

        #region Double Helpers

        public static bool IsInteger(this double target)
        {
            return Math.Truncate(target) == target;
        }

        /// <summary>
        /// Performs a bitwise AND operation agains a double
        /// </summary>
        /// <param name="t1">The first double (target of the extension method)</param>
        /// <param name="t2">The second Double</param>
        /// <returns></returns>
        public static double And(this double t1,double t2)
        {
            var whole1 = (long)Math.Truncate(t1);
            var whole2 = (long)Math.Truncate(t2);

            var frac1 = (long)((t1 - whole1) * 10e11);
            var frac2 = (long)((t2 - whole2) * 10e11);

            var wholeResult = (double)(whole1 & whole2);
            var fracResult = (double)(frac1 & frac2);
            var result = wholeResult + (fracResult / 10e11);

            return result;
        }

        /// <summary>
        /// Performs a bitwise OR operation agains a double
        /// </summary>
        /// <param name="t1">The first double (target of the extension method)</param>
        /// <param name="t2">The second Double</param>
        /// <returns></returns>
        public static double Or(this double t1, double t2)
        {
            var whole1 = (long)Math.Truncate(t1);
            var whole2 = (long)Math.Truncate(t2);

            var frac1 = (long)((t1 - whole1) * 10e11);
            var frac2 = (long)((t2 - whole2) * 10e11);

            var wholeResult = (double)(whole1 | whole2);
            var fracResult = (double)(frac1 | frac2);
            var result = wholeResult + (fracResult / 10e11);

            return result;
        }

        /// <summary>
        /// Performs a bitwise XOR operation agains a double
        /// </summary>
        /// <param name="t1">The first double (target of the extension method)</param>
        /// <param name="t2">The second Double</param>
        /// <returns></returns>
        public static double Xor(this double t1, double t2)
        {
            var whole1 = (long)Math.Truncate(t1);
            var whole2 = (long) Math.Truncate(t2);

            var frac1 = (long)((t1 - whole1)*10e11);
            var frac2 = (long)((t2 - whole2)*10e11);

            var wholeResult = (double) (whole1 ^ whole2);
            var fracResult = (double) (frac1 ^ frac2);
            var result = wholeResult + (fracResult/10e11);

            return result;
        }

        /// <summary>
        /// Performs a bitwise flip
        /// </summary>
        /// <param name="t1">The first double (target of the extension method)</param>
        /// <returns></returns>
        public static double Flip(this double t1)
        {
            var t1Bits = BitConverter.DoubleToInt64Bits(t1);
            var result = ~t1Bits;
            return BitConverter.Int64BitsToDouble(result);
        }

        #endregion

        #region Lambda Helpers

        public static Expression<Func<MathValue>> ToExpression(this Func<MathValue> target)
        {
            Expression<Func<MathValue>> result   =()=> target();
            return result;
        }

        #endregion

    }
}